package org.ala.tree.lsm.wal;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

import org.ala.tree.lsm.memtable.MemTableOpEnums;
import org.ala.tree.lsm.tools.KryoTools;
import org.ala.tree.lsm.wal.Wal.IWalReadConsumer;

/**
 *
 * @author ala
 * @date 2025年5月26日
 */
public class WalReader {

	

	/**
	 * 文件channel
	 */
	protected FileChannel fileChannel;
	
	public WalReader(Path filePath) throws IOException {
		fileChannel = FileChannel.open(filePath, StandardOpenOption.READ);
	}
	
	
	/**
	 * 	读取缓冲区大小
	 */
	protected int bufferSize;
	/**
	 * 	读取缓冲区
	 */
	protected ByteBuffer buffer;
	/**
	 * 	逐个读取
	 * @throws IOException 
	 */
	public <K,V> void read(String id, int file, Class<V> vclass, IWalReadConsumer<V> consumer) throws IOException {
		//	数据头长5字节
		ByteBuffer headBuffer = ByteBuffer.allocateDirect(Wal.HEAD_LEN);
		ByteBuffer bodyBuffer = null;
		//	读数据头
		int r = -1;
		while ((r = fileChannel.read(headBuffer)) > 0)  {
			if (r < Wal.HEAD_LEN) {
				headBuffer.clear();
				fileChannel.close();
				return;
			}
			headBuffer.flip();
			MemTableOpEnums op = MemTableOpEnums.getVal(headBuffer.get());
			int keyLen = headBuffer.getInt(),
				valLen = headBuffer.getInt();
			int len = keyLen + valLen;
			headBuffer.clear();

			bodyBuffer = ByteBuffer.allocateDirect(len);
			r = fileChannel.read(bodyBuffer);
			if (len == 0 || r < len) {
				bodyBuffer.clear();
				fileChannel.close();
				return;
			}
			byte[] keyBytes = new byte[keyLen],
				   valBytes = new byte[valLen];
			bodyBuffer.flip();
			bodyBuffer.get(keyBytes);
			bodyBuffer.get(valBytes);
			//	clear仅仅是清空指针，堆外内存要等bodyBuffer的引用被gc时释放（暂时找不到释放方法，一旦内存侧漏，改用堆内）
			bodyBuffer.clear();
			bodyBuffer = null;
			
			String k = KryoTools.deSerialize(keyBytes, String.class);
			V v = KryoTools.deSerialize(valBytes, vclass);
			consumer.accept(id, file, op, k, v);
		}
	}
}
